#include "Heuristique.h"


Heuristique::Heuristique(coord mapSize)
{
	_mapSize=mapSize;
	_amis=vector<groupe>();
	_ennemis=vector<groupe>();
	_humains=vector<groupe>();
	_force=0;
	_forceAdverse=0;
}


Heuristique::~Heuristique(void)
{
}

double Heuristique::compute(vector<groupe> amis, vector<groupe> ennemis, vector<groupe> humains)
{
	_amis=amis;
	_ennemis=ennemis;
	_humains=humains;
	int nh=_humains.size();
	int na=_amis.size();
	int ne=_ennemis.size();

	vector<double> r = reachability();
	vector<double> k = killability();
	double A;
	for(int i=0; i<nh; i++)
	{
		A += r[i]*k[i]*_humains[i].nombre;
	}
	for(int i=0; i<na; i++)
	{
		A += 2*_amis[i].nombre;
	}

	vector<double> re = reachability();
	vector<double> ke = killability();
	double E;
	for(int i=0; i<nh; i++)
	{
		E += re[i]*ke[i]*_humains[i].nombre;
	}
	for(int i=0; i<ne; i++)
	{
		E += 2*_ennemis[i].nombre;
	}


	return A-E;
}

vector<double> Heuristique::reachability()
{
	int nh=_humains.size();
	int na=_amis.size();
	int ne=_ennemis.size();
	vector<double> T;

	for(int i=0; i<nh; i++)
	{
		double pos=0;
		double min_da=max(_mapSize.x, _mapSize.y);
		for(int a=0; a<na; a++)
		{
			double da=distance(_humains[i].pos, _amis[a].pos);
			pos=pos+(1.0/(5.0*sqrt(2*M_PI)))*exp((-(da*da))/(50.0));
			if(da<min_da)
			{
				min_da=da;
			}
		}
		double neg=0;
		double min_de=max(_mapSize.x, _mapSize.y);
		for(int e=0; e<ne; e++)
		{
			double de=distance(_humains[i].pos, _ennemis[e].pos);
			neg=neg+(1.0/(5.0*sqrt(2*M_PI)))*exp((-(de*de))/(50.0));
			if(de<min_de)
			{
				min_de=de;
			}
		}
		if(min_de>min_da)
		{
			T.push_back(max(0.0, 2.0*((pos/(pos+neg)) - 0.5)));
		}
	}

	return T;
}

vector<double> Heuristique::killability()
{
	int nh=_humains.size();
	int na=_amis.size();
	int ne=_ennemis.size();
	vector<double> T;

	for(int i=0; i<nh; i++)
	{
		double min = max(_mapSize.x, _mapSize.y);
		double imin = 1;
		for(int j=0; j<na; j++)
		{
			double d=distance(_amis[j].pos, _humains[i].pos);
			if(d<min)
			{
				min=d;
				imin=j;
			}
		}
		double gain = 0;
		double dist = distance(_amis[imin].pos, _humains[i].pos);
		for(int j=0; j<nh; j++)
		{
			if(j!=i)
			{
				double d1=distance(_amis[imin].pos, _humains[j].pos);
				double d2=distance(_humains[i].pos, _humains[j].pos);
				if((d1+d2) == dist)
				{
					if(_humains[j].nombre>gain)
					{
						gain = _humains[j].nombre;
					}
				}
			}
		}
		if(_amis[imin].nombre+gain>=_humains[i].nombre)
		{
			T.push_back(1.0);
		}
		else
		{
			T.push_back(0.5);
		}
	}
	return T;
}

inline int Heuristique::distance(coord a, coord b)
{
	return (abs(a.x-b.x)>abs(a.y-b.y))? abs(a.x-b.x) : abs(a.y-b.y);
}

